<script setup lang="ts">
import { computed, reactive, ref, watch } from "vue";
import type { FormInstance, FormRules } from "element-plus";
import type {
  TemplateChannelMap,
  TemplateItem,
  TemplatePayload
} from "@/api/system/notify/template";

const DEFAULT_CHANNEL_OPTIONS = ["websocket", "wechat", "sms", "email"];

const CHANNEL_LABELS: Record<string, string> = {
  websocket: "WebSocket",
  wechat: "微信",
  sms: "短信",
  email: "邮箱",
  dingTalk: "钉钉",
  dingtalk: "钉钉",
  lark: "飞书",
  feishu: "飞书",
  app: "App",
  push: "推送"
};

interface Props {
  mode?: "create" | "edit";
  template?: TemplateItem | null;
  categories?: string[];
  channelOptions?: string[];
  onSubmit?: (payload: TemplatePayload) => Promise<void>;
}

const props = defineProps<Props>();

const emit = defineEmits<{
  (e: "submitted", payload: TemplatePayload): void;
}>();

interface TemplateFormModel {
  name: string;
  title: string;
  content: string;
  type: string;
  category: string;
  status: number;
  description: string;
  channels: TemplateChannelMap;
}

const formRef = ref<FormInstance>();
const submitting = ref(false);

const formModel = reactive<TemplateFormModel>({
  name: "",
  title: "",
  content: "",
  type: "",
  category: "",
  status: 1,
  description: "",
  channels: {}
});

const categoryOptions = computed(() => props.categories ?? []);

const suppliedChannelOptions = computed(
  () =>
    (props.channelOptions?.length ? props.channelOptions : null) ??
    DEFAULT_CHANNEL_OPTIONS
);

const channelKeys = computed(() => {
  const keys = new Set<string>();
  suppliedChannelOptions.value.forEach(key => keys.add(key));
  Object.keys(formModel.channels ?? {}).forEach(key => keys.add(key));
  return Array.from(keys);
});

const rules: FormRules<TemplateFormModel> = {
  name: [{ required: true, message: "请输入模板名称", trigger: "blur" }],
  type: [
    { required: true, message: "请填写模板标识", trigger: "blur" },
    {
      pattern: /^[a-zA-Z][a-zA-Z0-9_.-]{2,63}$/,
      message: "以字母开头，可含数字/._-，长度 3-64 位",
      trigger: "blur"
    }
  ],
  title: [{ required: true, message: "请输入通知标题", trigger: "blur" }],
  content: [{ required: true, message: "请输入通知内容", trigger: "blur" }]
};

const channelLabel = (channel: string) => {
  const key = channel?.toString?.() ?? "";
  const lower = key.toLowerCase();
  return CHANNEL_LABELS[lower] ?? CHANNEL_LABELS[key] ?? key ?? "-";
};

const ensureChannelEntries = () => {
  channelKeys.value.forEach(channel => {
    if (!formModel.channels[channel]) {
      formModel.channels[channel] = {
        enabled: channel === "websocket",
        route: ""
      };
    }
  });
};

const resetFormModel = () => {
  formModel.name = "";
  formModel.title = "";
  formModel.content = "";
  formModel.type = "";
  formModel.category = "";
  formModel.status = 1;
  formModel.description = "";
  Object.keys(formModel.channels).forEach(key => {
    delete formModel.channels[key];
  });
  ensureChannelEntries();
};

const assignTemplate = (template?: TemplateItem | null) => {
  resetFormModel();
  if (!template) {
    return;
  }
  formModel.name = template.name ?? "";
  formModel.title = template.title ?? "";
  formModel.content = template.content ?? "";
  formModel.type = template.type ?? "";
  formModel.category = template.category ?? "";
  formModel.status = Number(template.status ?? 1) as 0 | 1 | number;
  formModel.description = template.description ?? template.remark ?? "";
  Object.keys(formModel.channels).forEach(key => {
    delete formModel.channels[key];
  });
  Object.entries(template.channels ?? {}).forEach(([channel, config]) => {
    formModel.channels[channel] = {
      enabled: Boolean(config?.enabled),
      route: config?.route ?? ""
    };
  });
  ensureChannelEntries();
};

watch(
  () => props.template,
  template => {
    assignTemplate(template);
  },
  { immediate: true }
);

watch(
  () => suppliedChannelOptions.value,
  () => {
    ensureChannelEntries();
  },
  { immediate: true }
);

const buildChannelsPayload = (): TemplateChannelMap => {
  const payload: TemplateChannelMap = {};
  channelKeys.value.forEach(channel => {
    const config = formModel.channels[channel] ?? {
      enabled: false,
      route: ""
    };
    payload[channel] = {
      enabled: Boolean(config.enabled),
      route: config.route ?? ""
    };
  });
  return payload;
};

const submitForm = async () => {
  try {
    await formRef.value?.validate();
  } catch {
    return false;
  }

  if (!props.onSubmit) {
    return true;
  }

  const payload: TemplatePayload = {
    name: formModel.name.trim(),
    title: formModel.title.trim(),
    content: formModel.content,
    type: formModel.type.trim(),
    category: formModel.category.trim() || undefined,
    status: Number(formModel.status ?? 1),
    description: formModel.description.trim() || undefined,
    channels: buildChannelsPayload()
  };

  submitting.value = true;
  try {
    await props.onSubmit(payload);
    emit("submitted", payload);
    return true;
  } catch (error) {
    return false;
  } finally {
    submitting.value = false;
  }
};

defineExpose({ submitForm });
</script>

<template>
  <div v-loading="submitting" class="notify-template-form">
    <el-form
      ref="formRef"
      :model="formModel"
      :rules="rules"
      label-width="110px"
    >
      <el-form-item label="模板名称" prop="name">
        <el-input
          v-model.trim="formModel.name"
          placeholder="请输入模板名称"
          autocomplete="off"
        />
      </el-form-item>
      <el-form-item label="类型标识" prop="type">
        <el-input
          v-model.trim="formModel.type"
          placeholder="例如 order_paid、spotcheck"
          autocomplete="off"
        />
      </el-form-item>
      <el-form-item label="标题" prop="title">
        <el-input
          v-model.trim="formModel.title"
          placeholder="通知标题，支持占位符"
          autocomplete="off"
        />
      </el-form-item>
      <el-form-item label="内容" prop="content">
        <el-input
          v-model="formModel.content"
          type="textarea"
          :rows="6"
          placeholder="通知内容，可使用 {variable} 占位符"
        />
      </el-form-item>
      <el-form-item label="分类">
        <el-select
          v-model="formModel.category"
          class="w-full"
          filterable
          allow-create
          default-first-option
          placeholder="请选择或输入分类"
        >
          <el-option
            v-for="item in categoryOptions"
            :key="item"
            :label="item"
            :value="item"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="状态">
        <el-switch
          v-model="formModel.status"
          :active-value="1"
          :inactive-value="0"
          active-text="启用"
          inactive-text="停用"
        />
      </el-form-item>
      <el-form-item label="描述">
        <el-input
          v-model.trim="formModel.description"
          type="textarea"
          :rows="3"
          placeholder="用于标记或备注模板用途"
        />
      </el-form-item>
      <el-form-item label="渠道配置">
        <div class="channel-grid">
          <div
            v-for="channel in channelKeys"
            :key="channel"
            class="channel-item"
          >
            <div class="channel-item__header">
              <span class="channel-item__name">
                {{ channelLabel(channel) }}
              </span>
              <el-switch
                v-model="formModel.channels[channel].enabled"
                inline-prompt
                active-text="开"
                inactive-text="关"
              />
            </div>
            <el-input
              v-model="formModel.channels[channel].route"
              :placeholder="`推送路由/地址（${channel}）`"
              :disabled="!formModel.channels[channel].enabled"
            />
            <span class="channel-item__hint">
              {{ channelLabel(channel) }} 推送路径，支持占位符
            </span>
          </div>
        </div>
      </el-form-item>
    </el-form>
  </div>
</template>

<style scoped>
.notify-template-form {
  padding: 8px 4px;
}

.channel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  width: 100%;
}

.channel-item {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  border: 1px solid var(--el-border-color-light);
  border-radius: 6px;
  background-color: var(--el-fill-color-light);
}

.channel-item__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.channel-item__name {
  font-weight: 500;
  color: var(--el-text-color-primary);
}

.channel-item__hint {
  font-size: 12px;
  color: var(--el-text-color-secondary);
}
</style>
